using System;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Collections;
using System.Drawing;
using System.Workflow.ComponentModel;
using System.Workflow.ComponentModel.Design;
using System.Workflow.ComponentModel.Compiler;
using System.Workflow.ComponentModel.Serialization;
using System.Workflow.Runtime;
using System.Workflow.Activities;
using System.Workflow.Activities.Rules;
using System.Reflection;
using System.Diagnostics;
using System.Runtime.Serialization;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using System.Collections.Generic;
using OpenComposite.Workflow.Properties;
using System.Drawing.Design;
using OpenComposite.Workflow.Interfaces;
using OpenComposite.Workflow.Extenders;

namespace OpenComposite.Workflow
{
	[Designer(typeof(LogicalCapabilityActivityDesigner))]
	[ActivityValidator(typeof(LogicalCapabilityActivityValidator))]
	[ToolboxItem(typeof(LogicalCapabilityActivityToolboxItem))]
	[ToolboxBitmap(typeof(resfinder), "OpenComposite.Workflow.Resources.logact_sync.png")]
	public partial class LogicalCapabilityActivity
		: Activity, ITrackingActivity, ILogicalActivity, ITextActivity
	{
		#region Initialization
		public LogicalCapabilityActivity()
		{
			InitializeComponent();
			HasOutputObject = false;
			this.Canceling += new EventHandler<ActivityExecutionStatusChangedEventArgs>(LogicalCapabilityActivity_Canceling);
			this.Compensating += new EventHandler<ActivityExecutionStatusChangedEventArgs>(LogicalCapabilityActivity_Compensating);
		}

		#endregion

		#region Public Members

		#region Properties

		#region ActivitiesClass
		public static DependencyProperty ActivitiesClassProperty = DependencyProperty.Register(
			"ActivitiesClass", typeof(object), typeof(LogicalCapabilityActivity), new PropertyMetadata(null));
		[Category("Logical Capability")]
#if DEBUG
		[Browsable(true)]
#else
		[Browsable(false)]
#endif
		public object ActivitiesClass
		{
			get { return base.GetValue(LogicalCapabilityActivity.ActivitiesClassProperty); }
			set { base.SetValue(LogicalCapabilityActivity.ActivitiesClassProperty, value); }
		}
		#endregion

		#region LogicalActivityName
		public static DependencyProperty LogicalActivityNameProperty =
			DependencyProperty.Register("LogicalActivityName", typeof(string),
										typeof(LogicalCapabilityActivity), new PropertyMetadata(null));
#if DEBUG
		[Browsable(true)]
#else
		[Browsable(false)]
#endif
		[Category("Logical Capability")]
		public string LogicalActivityName
		{
			get { return (string)GetValue(LogicalActivityNameProperty); }
			set { SetValue(LogicalActivityNameProperty, value); }
		}

		#endregion

		#region LogicalActivityId
		public static DependencyProperty LogicalActivityIdProperty =
			DependencyProperty.Register("LogicalActivityId", typeof(int),
										typeof(LogicalCapabilityActivity), new PropertyMetadata(DependencyPropertyOptions.Metadata));
#if DEBUG
		[Browsable(true)]
#else
		[Browsable(false)]
#endif
		[Category("Logical Capability")]
		public int LogicalActivityId
		{
			get { return (int)GetValue(LogicalActivityIdProperty); }
			set { SetValue(LogicalActivityIdProperty, value); }
		}
		#endregion

		#region HasOutputObject
		public static DependencyProperty HasOutputObjectProperty =
			DependencyProperty.Register("HasOutputObject", typeof(bool),
										typeof(LogicalCapabilityActivity), new PropertyMetadata(DependencyPropertyOptions.Metadata));
#if DEBUG
		[Browsable(true)]
#else
		[Browsable(false)]
#endif
		[Category("Logical Capability")]
		public bool HasOutputObject
		{
			get { return (bool)GetValue(HasOutputObjectProperty); }
			set { SetValue(HasOutputObjectProperty, value); }
		}
		#endregion

		#region Type
		public static DependencyProperty TypeProperty =
			DependencyProperty.Register("Type", typeof(LogicalCapabilityType),
								typeof(LogicalCapabilityActivity), new PropertyMetadata(LogicalCapabilityType.LogicalCapability));
		[Browsable(true)]
		[Category("Logical Capability")]
		public LogicalCapabilityType Type
		{
			get { return (LogicalCapabilityType)GetValue(TypeProperty); }
			set { SetValue(TypeProperty, value); }
		}

		#endregion

		#region Text
		public static DependencyProperty TextProperty = DependencyProperty.Register(
			"Text", typeof(string), typeof(LogicalCapabilityActivity), new PropertyMetadata(""));
		[Editor(typeof(MultilineStringEditor), typeof(UITypeEditor))]
		[DefaultValue("")]
		[Browsable(true)]
		[Category("Logical Capability")]
		public string Text
		{
			get
			{
				string text = (string)base.GetValue(LogicalCapabilityActivity.TextProperty);
				if ( string.IsNullOrEmpty(text) ) return this.Name;
				return text;
			}
			set { base.SetValue(LogicalCapabilityActivity.TextProperty, value); }
		}

		DependencyProperty ITextActivity.GetTextProperty()
		{
			return TextProperty;
		}
		#endregion

		#region Capability
		public static DependencyProperty CapabilityProperty =
			DependencyProperty.Register("Capability", typeof(string),
										typeof(LogicalCapabilityActivity), new PropertyMetadata(null));
		[Browsable(true)]
		[DesignOnly(true)]
		[ReadOnly(true)]
		[Category("Logical Capability")]
		public string Capability
		{
			get { return (string)GetValue(CapabilityProperty); }
			set { SetValue(CapabilityProperty, value); }
		}
		#endregion

		#endregion

		#endregion

		#region Protected Members

		#region Methods
		// override
		protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
		{
			base.Invoke(this.ContinueAt, EventArgs.Empty);
			return ActivityExecutionStatus.Executing;
		}
		private void ContinueAt(object sender, EventArgs e)
		{
			ActivityExecutionContext context = sender as ActivityExecutionContext;
			object activitiesclass = this.ActivitiesClass;
			Type t = activitiesclass.GetType();
			if ( t != null ) {
				MethodInfo mi = t.GetMethod(this.LogicalActivityName);
				if ( mi != null ) {
					mi.Invoke(activitiesclass, new object[] { context, (ITrackingActivity)this });
				}
			}
			context.CloseActivity();
		}
		#endregion

		#endregion

		#region Private Members

		#region Event Handlers

		private void LogicalCapabilityActivity_Canceling(object sender, ActivityExecutionStatusChangedEventArgs e)
		{
		}

		private void LogicalCapabilityActivity_Compensating(object sender, ActivityExecutionStatusChangedEventArgs e)
		{
		}

		#endregion

		#endregion

		#region ITrackingActivity Members

		public void AddKPIData(string sKPIName, string sKPIValue, string sKPIUnit, string sKPIDataType)
		{
			this.TrackData(sKPIName, new KPITrackingData(sKPIName, sKPIValue, sKPIUnit, sKPIDataType));
		}

		public void AddBusinessObjectData(string sBOName, object sBOValue)
		{
			this.TrackData(sBOName, new BusinessObjectTrackingData(sBOName, sBOValue));
		}

		#endregion
	}


	#region Class: LogicalCapabilityActivityValidator : ActivityValidator
	public class LogicalCapabilityActivityValidator : ActivityValidator
	{
		public static event EventHandler Validating;
		public override ValidationErrorCollection Validate(ValidationManager manager, object obj)
		{
			EventHandler tmp = LogicalCapabilityActivityValidator.Validating;
			if ( tmp != null ) {
				tmp(obj, EventArgs.Empty);
			}
			ValidationErrorCollection errors = base.Validate(manager, obj);
			LogicalCapabilityActivity logcap = obj as LogicalCapabilityActivity;
			if ( logcap != null ) {
				if ( logcap.LogicalActivityId <= 0 ) {
					errors.Add(new ValidationError("No capability assigned.", 7000));
				}
			}
			return errors;
		}
	}
	#endregion

	#region Class: LogicalCapabilityActivityToolboxItem : Base: ActivityToolboxItem
	[Serializable]
	public class LogicalCapabilityActivityToolboxItem : ActivityToolboxItem
	{
		public LogicalCapabilityActivityToolboxItem(Type type)
			: base(type)
		{
			base.DisplayName = "Logical Capability";
		}

		private object _tag;
		public object Tag
		{
			get { return _tag; }
			set { _tag = value; }
		}

		public event EventHandler<InitializeLogicalCapabilityActivityEventArgs>
			InitializeLogicalCapabilityActivity = null;

		protected override IComponent[] CreateComponentsCore(IDesignerHost host)
		{
			LogicalCapabilityActivity act = new LogicalCapabilityActivity();

			OnInitializeLogicalCapabilityActivity(act);

			return new IComponent[] { act };
		}
		protected virtual void OnInitializeLogicalCapabilityActivity(LogicalCapabilityActivity logact)
		{
			EventHandler<InitializeLogicalCapabilityActivityEventArgs> tmp = this.InitializeLogicalCapabilityActivity;
			if ( tmp != null )
				tmp(this, new InitializeLogicalCapabilityActivityEventArgs(logact));
		}

		private LogicalCapabilityActivityToolboxItem(SerializationInfo info, StreamingContext context)
		{
			Deserialize(info, context);
		}

	}
	[Serializable]
	public class InitializeLogicalCapabilityActivityEventArgs : EventArgs
	{
		public InitializeLogicalCapabilityActivityEventArgs(LogicalCapabilityActivity logact)
		{
			_logact = logact;
		}
		private LogicalCapabilityActivity _logact;
		public LogicalCapabilityActivity LogicalCapabilityActivity
		{
			get { return _logact; }
		}
	}
	#endregion

	#region Class: LogicalCapabilityActivityDesigner : Base: ExtendedActivityDesigner
	[ActivityDesignerTheme(typeof(LogicalCapabilityActivityDesignerTheme))]
	public class LogicalCapabilityActivityDesigner : ExtendedActivityDesigner
	{
		public LogicalCapabilityActivityDesigner()
		{
		}

		private bool expanded = true;
		private bool useBasePaint = false;

		private HorizontalWorkflowDesigner root = null;

		public bool UseBasePaint
		{
			get { return this.useBasePaint; }
			set { this.useBasePaint = value; }
		}
		public LogicalCapabilityActivity LogicalCapability
		{
			get { return this.Activity as LogicalCapabilityActivity; }
		}
		public bool Expanded
		{
			get { return this.expanded; }
			set { this.expanded = value; }
		}

		public override Image Image
		{
			get
			{
				Image img = null;
				if ( this.LogicalCapability != null ) {
					switch ( this.LogicalCapability.Type ) {
						case LogicalCapabilityType.HumanActivityCapablity:
							img = Resources.user;
							break;
						case LogicalCapabilityType.CompositeCapablity:
							img = Resources.png_horizontalprocess;
							break;
					}
				}
				return img;
			}
			protected set
			{
				base.Image = value;
			}
		}

		protected override void Initialize(Activity activity)
		{
			base.Initialize(activity);
		}
		protected override void OnDragOver(ActivityDragEventArgs e)
		{
			try {
				if ( e.Data.GetDataPresent(typeof(TreeNode)) ) {
					object item = ( (TreeNode)e.Data.GetData(typeof(TreeNode)) ).Tag;
					Type t = item.GetType();
					PropertyInfo pi = t.GetProperty("RepositoryItemType", BindingFlags.Instance | BindingFlags.Public);
					int rit = (int)pi.GetValue(item, null);
					if ( rit == 14 /*Verb*/ || rit == 8 /*Operation*/ ) {
						setSelectedItem(this.Activity);
						e.Effect = DragDropEffects.Link;
					} else if ( rit == 58 /*Workflow*/) {
						if ( this.LogicalCapability.LogicalActivityId > 0 ) {
							setSelectedItem(this.Activity);
							e.Effect = DragDropEffects.Link;
						}
					}
				}
			} catch ( Exception ex ) {
				Debug.WriteLine(ex.ToString());
			}
			base.OnDragOver(e);
		}
		protected override void OnDragDrop(ActivityDragEventArgs e)
		{
			e.Effect = DragDropEffects.Link;
			bool handled = false;
			DesignerTransaction trans = null;
			IDesignerHost designerHost = GetService(typeof(IDesignerHost)) as IDesignerHost;
			if ( designerHost != null ) {
				trans = designerHost.CreateTransaction();
			}
			this.ParentView.SuspendLayout();
			LogicalCapabilityActivity logact = this.Activity as LogicalCapabilityActivity;
			Activity rootAct = WorkflowHelpers.GetRootActivity(logact);
			try {
				if ( e.Data.GetDataPresent(typeof(TreeNode)) ) {
					if ( logact != null ) {
						object item = ( (TreeNode)e.Data.GetData(typeof(TreeNode)) ).Tag;
						Type t = item.GetType();
						PropertyInfo pi = t.GetProperty("RepositoryItemType");
						int rit = (int)pi.GetValue(item, null);
						pi = t.GetProperty("ID");
						int id = (int)pi.GetValue(item, null);
						if ( rit == 14 /*Verb*/ ) {
							MethodInfo mi = t.GetMethod("AssignLogicalActivity");
							object objReturn = mi.Invoke(item, new object[] { logact.LogicalActivityId });
							if ( objReturn != null && objReturn.GetType().Name.Equals("LogicalActivity") ) {
								PropertyInfo piRetID = objReturn.GetType().GetProperty("ID");
								TypeDescriptor.GetProperties(logact)["LogicalActivityId"]
									.SetValue(logact, (int)piRetID.GetValue(objReturn, null));
								PropertyInfo piLAType = objReturn.GetType().GetProperty("LogicalActivityType");
								piLAType.SetValue(objReturn, 2/*LogicalCapability*/, null);
								MethodInfo miSave = objReturn.GetType().GetMethod("Save");
								miSave.Invoke(objReturn, null);
							}
							pi = t.GetProperty("Name");
							TypeDescriptor.GetProperties(logact)["LogicalActivityName"]
								.SetValue(logact, (string)pi.GetValue(item, null));
							PropertyDescriptor textProp = TypeDescriptor.GetProperties(logact)["Text"];
							PropertyDescriptor nameProp = TypeDescriptor.GetProperties(logact)["Name"];
							if ( textProp != null ) {
								string currentText = (string)textProp.GetValue(logact);
								if ( string.IsNullOrEmpty(currentText) ) {
									textProp.SetValue(logact, WorkflowHelpers.MakeNameWithSpaces((string)pi.GetValue(item, null)));
								}
							}
							PropertyInfo outputObject = t.GetProperty("OutputBusinessObject");
							try {
								if ( outputObject != null ) {
									object obj = outputObject.GetValue(item, null);
									bool hasOutput = obj != null;
									TypeDescriptor.GetProperties(logact)["HasOutputObject"]
										.SetValue(logact, hasOutput);
									if ( hasOutput ) {
										if ( Form.ModifierKeys != Keys.Alt ) {
											PropertyInfo propBobjName = obj.GetType().GetProperty("Name");
											string bobjName = propBobjName.GetValue(obj, null).ToString();
											TypeDescriptor.GetProperties(logact)["OutputVarName"]
												.SetValue(logact, string.Format("{0}_{1}", logact.Name, bobjName));
										}
									}
								}
							} catch { }
							string name = pi.GetValue(item, null).ToString();
							try {
								if ( Form.ModifierKeys != Keys.Alt && nameProp != null ) {
									// throws exception if name already exist -> no renaming!
									nameProp.SetValue(logact, WorkflowHelpers.EnsureUniqueName(logact, name));
									textProp.SetValue(logact, WorkflowHelpers.MakeNameWithSpaces(name));
								}
							} catch { }
							if ( rootAct != null ) {
								ActivityBind actbindIn = new ActivityBind(rootAct.Name, "LogicalActivitiesClass");
								logact.SetBinding(LogicalCapabilityActivity.ActivitiesClassProperty, actbindIn);
							}
						} else if ( rit == 8 /*Operation*/ ) {
							MethodInfo mi = t.GetMethod("AssignLogicalActivity");
							object objReturn = mi.Invoke(item, new object[] { logact.LogicalActivityId });
							if ( objReturn != null && objReturn.GetType().Name.Equals("LogicalActivity") ) {
								if ( logact.LogicalActivityId <= 0 ) {
									PropertyInfo piRetID = objReturn.GetType().GetProperty("ID");
									logact.LogicalActivityId = (int)piRetID.GetValue(objReturn, null);
									PropertyInfo piLAType = objReturn.GetType().GetProperty("LogicalActivityType");
									piLAType.SetValue(objReturn, 2/*LogicalCapability*/, null);
									MethodInfo miSave = objReturn.GetType().GetMethod("Save");
									miSave.Invoke(objReturn, null);
								}
							}
						} else if ( rit == 58 /*Workflow(Composite)*/ ) {
							if ( this.Activity.UserData.Contains("workflow") ) {
								this.Activity.UserData["workflow"] = id;
							} else {
								this.Activity.UserData.Add("workflow", id);
							}
							WorkflowHelpers.OnAssignWorkflow((LogicalCapabilityActivity)this.Activity);
						}
						this.Initialize(this.Activity);
						handled = true;
					}
				}
				if ( trans != null )
					trans.Commit();
			} catch ( Exception ex ) {
				Debug.WriteLine(ex.ToString());
				if ( trans != null )
					trans.Cancel();
			} finally {
				this.ParentView.ResumeLayout(true);
			}
			if ( !handled ) {
				setSelectedItem(null);
				base.OnDragDrop(e);
			} else {
				setSelectedItem(this.Activity, SelectionTypes.Primary);
			}
		}

		ISelectionService _selectionService = null;
		private void setSelectedItem(object item)
		{
			setSelectedItem(item, SelectionTypes.Primary);
		}
		private void setSelectedItem(object item, SelectionTypes selectionType)
		{
			if ( _selectionService == null ) {
				_selectionService = GetService(typeof(ISelectionService)) as ISelectionService;
			}
			if ( _selectionService != null ) {
				ArrayList al = new ArrayList();
				if ( item != null )
					al.Add(item);
				_selectionService.SetSelectedComponents(al, selectionType);
			}
		}

	}
	#endregion

	#region Class: AssignedCapabilityGlyph : DesignerGlyph
	sealed class ActivityStatusGlyph : DesignerGlyph
	{
		public ActivityStatusGlyph(ActivityStatus status)
		{
			Status = status;
		}

		public ActivityStatus Status { get; private set; }

		protected override void OnPaint(Graphics graphics, bool activated, AmbientTheme ambientTheme, ActivityDesigner designer)
		{
			float width = 8;
			float height = 8;

			Bitmap image = Resources.status_error;
			if ( Status == ActivityStatus.Ready ) {
				image = Resources.status_ok;
			}

			graphics.DrawImage(image,
				designer.Bounds.Right, designer.Location.Y - height / 2,
				width, height);
		}
	}

	public enum ActivityStatus
	{
		Unknown = 0,
		Ready = 1,
		Error = 2,
	}
	#endregion

	#region Class: LogicalCapabilityActivityDesignerTheme : Base: ActivityDesignerTheme
	public class LogicalCapabilityActivityDesignerTheme : ActivityDesignerTheme
	{
		public LogicalCapabilityActivityDesignerTheme(WorkflowTheme theme)
			: base(theme)
		{
			base.Initialize();
			this.BorderStyle = DashStyle.Solid;
			this.BorderColor = Color.CornflowerBlue;
			this.BackColorStart = Color.White;
			this.BackColorEnd = Color.CornflowerBlue;
			this.BackgroundStyle = LinearGradientMode.ForwardDiagonal;
			this.ForeColor = Color.Black;
		}

	}
	#endregion

	#region Enum: LogicalCapabilityType
	public enum LogicalCapabilityType
	{
		LogicalCapability,
		CompositeCapablity,
		HumanActivityCapablity,
		AtomicWS,
		ExternalAtomicWS,
		EndPointWS,
		ExternalEndPointWS,
		ItSystem,
		Selector,
		MulitpleHA,
		AsyncStart
	}
	#endregion
}
